package com.dongnao.jack.spring.parse;

import java.io.Serializable;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.dongnao.jack.invocate.HttpRegistryInvocate;
import com.dongnao.jack.invocate.RegistryInvocate;
import com.dongnao.jack.invocate.RegistryInvocationHandler;
import com.dongnao.jack.invocate.RmiRegistryInvocate;
import com.dongnao.jack.registry.handler.RegistryDelegate;

/**
 * 
 * @ClassName: ReferenceConfig 
 * @Description: 消费端springBean的定义。
 * @author xuyp
 * @date 2018年4月17日 下午2:01:21 
 *
 */
public class ReferenceConfig implements Serializable, FactoryBean<Object>, ApplicationContextAware, InitializingBean {

    /** 
     * @Fields serialVersionUID :
     */
    private static final long serialVersionUID = -3972868870786874869L;

    /**
     * 当前消费端bean在spring容器的id
     */
    private String id;

    /**
     * 当前服务bean实现的接口全路径
     */
    private String interfaceClass;

    /**
     * 通过框架调用使用的接口进行的均衡算法（随机，轮询，参数一致性hash算法）
     */
    private String loadbalance;

    /**
     * 调用服务使用的类型（http）
     */
    private String protocol;

    private String temRef;

    private ApplicationContext applicationContext;

    private List<String> registerList;

    public String getTemRef() {
        return temRef;
    }

    public void setTemRef(String temRef) {
        this.temRef = temRef;
    }

    public List<String> getRegisterList() {
        return registerList;
    }

    public void setRegisterList(List<String> registerList) {
        this.registerList = registerList;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getInterfaceClass() {
        return interfaceClass;
    }

    public void setInterfaceClass(String interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    public String getLoadbalance() {
        return loadbalance;
    }

    public void setLoadbalance(String loadbalance) {
        this.loadbalance = loadbalance;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    @Override
    public String toString() {
        return "ReferenceConfig [id=" + id + ", interfaceClass=" + interfaceClass + ", loadbalance=" + loadbalance
                + ", protocol=" + protocol + "]";
    }

    public static Map<String, RegistryInvocate> invocates = new HashMap<>();

    static {
        invocates.put("http", new HttpRegistryInvocate());
        invocates.put("rmi", new RmiRegistryInvocate());
        invocates.put("netty", null);
    }

    /**
     * 
     * <p>Overriding Method of getObject</p>  
     * <p>Description: 产生代理对象</p> 
     * @return
     * @throws Exception 
     * @see org.springframework.beans.factory.FactoryBean#getObject() 
     * @author xuyp
     * @date 2018年4月19日 上午10:15:30
     */
    @Override
    public Object getObject() throws Exception {

        if (StringUtils.isNoneBlank(interfaceClass)) {
            RegistryInvocate invocate;
            if (StringUtils.isNoneBlank(protocol)) {
                invocate = invocates.get(protocol);
            } else {
                ProtocolConfig bean = applicationContext.getBean(ProtocolConfig.class);
                if (bean != null) {

                    invocate = invocates.get(bean.getName());
                } else {
                    invocate = invocates.get("http");
                }
            }

            return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                    new Class[] { Class.forName(interfaceClass) }, new RegistryInvocationHandler(invocate, this));

        }

        return null;
    }

    @Override
    public Class<?> getObjectType() {

        if (StringUtils.isNoneBlank(interfaceClass)) {
            try {
                return Class.forName(interfaceClass);
            }
            catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        registerList = RegistryDelegate.getRegistry(this);

    }

}
